/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package com.jili.ubert.server.tradecore;

import com.jili.ubert.code.client2server.BasketOrders;
import com.jili.ubert.code.server2client.MsgResult;
import com.jili.ubert.code.server2client.MsgResultList;
import com.jili.ubert.code.server2client.Price;
import com.jili.ubert.dao.db.AccountBail;
import com.jili.ubert.dao.db.AccountFare;
import com.jili.ubert.dao.db.AccountInfo;
import com.jili.ubert.dao.db.AlterOrder;
import com.jili.ubert.dao.db.FundState;
import com.jili.ubert.dao.db.NewOrder;
import com.jili.ubert.dao.db.PosDetail;
import com.jili.ubert.dao.db.TradeReportDetail;
import com.jili.ubert.server.adapter.OnPrice;
import com.jili.ubert.server.datapool.DataPoolTrade;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
import javax.persistence.EntityManager;
import javax.persistence.Query;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 *
 * @author ChengJiLi
 */
public class TradeCoreLib implements OnPrice {

    private static final Log log = LogFactory.getLog(TradeCoreLib.class);
    private final ConcurrentHashMap<String, Position> posTable = new ConcurrentHashMap<>();
    private AtomicInteger orderid = new AtomicInteger(1);
    private DataPoolTrade datapool;

    public TradeCoreLib() {
    }

    public TradeCoreLib(DataPoolTrade datapool) {
        this.datapool = datapool;
    }

    public int getOrderID() {
        return orderid.getAndIncrement();
    }

    public void init() {
        /*
         0.筛选数据，1.读结算，费率，保证金，出入金，回报，在途委托，2.处理当日数据，3.准备服务
         */
        if (datapool != null) {
            EntityManager em = datapool.getDBFactory().createEntityManager();
            Query query = em.createNamedQuery("AccountInfo.findByIsRisk", AccountInfo.class);
            query.setParameter(1, "1");
            List<AccountInfo> acctable = query.getResultList();
            acctable.stream().forEach((AccountInfo acc) -> {
                String acccode = acc.getAccountCode();
                String region = acc.getRegionID();
                String sf = acc.getItype();
                String type = acc.getType();
                Position pos = posFactory(region, sf, type);
                loadPosition(acccode,pos);
                prepareOrder(acccode,pos);
            });
        } else {
            log.info("数据池不可用");
        }
    }

    private Position posFactory(String region, String sf, String type) {
        switch (region) {
            case "C": {
                if (sf.equals("S")) {
                    if (type.equals("S")) {
                        return new PositionCSS();
                    } else {
                        return new PositionCST();
                    }
                } else if (type.equals("S")) {
                    return new PositionCFS();
                } else {
                    return new PositionCFT();
                }
            }
            case "H": {
                if (sf.equals("S")) {
                    if (type.equals("S")) {
                        return new PositionHSS();
                    } else {
                        return new PositionHST();
                    }
                } else if (type.equals("S")) {
                    return new PositionHFS();
                } else {
                    return new PositionHFT();
                }
            }
            default: {
                if (sf.equals("S")) {
                    if (type.equals("S")) {
                        return new PositionCSS();
                    } else {
                        return new PositionCST();
                    }
                } else if (type.equals("S")) {
                    return new PositionCFS();
                } else {
                    return new PositionCFT();
                }
            }
        }
    }

    public void loadAccountTradeData(String acc) {
        if (!posTable.containsKey(acc)) {
            EntityManager em = datapool.getDBFactory().createEntityManager();
            Query query = em.createNamedQuery("AccountInfo.findByAccountCode", AccountInfo.class);
            query.setParameter(1, acc);
            AccountInfo acctable = (AccountInfo) query.getSingleResult();
            Position pos = posFactory(acctable.getRegionID(),acctable.getItype(),acctable.getType());
            loadPosition(acc,pos);
        }
    }

    public void reloadAccountTradeData(String acc) {
        if (posTable.containsKey(acc)) {
            posTable.remove(acc);
        }
        loadAccountTradeData(acc);
    }

    public void loadPosition(String acc, Position pos) {
        EntityManager em = datapool.getDBFactory().createEntityManager();
        Query queryfare = em.createNamedQuery("AccountFare.findByAccountCode", AccountFare.class);
        queryfare.setParameter(1, acc);
        List<AccountFare> faretable = queryfare.getResultList();
        faretable.stream().forEach((AccountFare afare)->{pos.setData(new Fare(afare));});
        Query querybail = em.createNamedQuery("AccountBail.findByAccountCode", AccountBail.class);
        querybail.setParameter(1, acc);
        List<AccountBail> bailtable = querybail.getResultList();
        bailtable.stream().forEach((AccountBail afare)->{pos.setData(new Bail(afare));});
        Query queryfund = em.createNamedQuery("FundState.findByAccountCode", FundState.class);
        queryfund.setParameter(1, acc);
        FundState fund = (FundState)queryfund.getSingleResult();
        pos.setData(fund);
        Query querypos = em.createNamedQuery("PosDetail.findByAccountCode", PosDetail.class);
        querypos.setParameter(1, acc);
        List<PosDetail> postable = querypos.getResultList();
        postable.stream().forEach((PosDetail afare)->{pos.setData(new PosRecord(afare));});  
        
        this.posTable.put(acc, pos);
    }
    private void prepareOrder(String acc, Position pos){
        EntityManager em = datapool.getDBFactory().createEntityManager();
        Query qury = em.createQuery("SELECT t FROM TradeReportDetail t WHERE t.accountCode = :accountCode AND t.msgType = 'OR'", TradeReportDetail.class);
        qury.setParameter(1, acc);
        List<TradeReportDetail> faretable0 = qury.getResultList();
        faretable0.stream().forEach((TradeReportDetail afare)->{pos.OnReportOrderConfirm(afare);});
        Query qury2 = em.createQuery("SELECT t FROM TradeReportDetail t WHERE t.accountCode = :accountCode AND t.msgType = 'OR'", TradeReportDetail.class);
        qury2.setParameter(1, acc);
        List<TradeReportDetail> faretable2 = qury.getResultList();
        faretable2.stream().forEach((TradeReportDetail afare)->{pos.OnReportOrderConfirm(afare);});
        Query queryfare = em.createNamedQuery("TradeReportDetail.findByAccountCode", TradeReportDetail.class);
        queryfare.setParameter(1, acc);
        List<TradeReportDetail> faretable = queryfare.getResultList();
        faretable.stream().forEach((TradeReportDetail afare)->{pos.OnTradeReport(afare);});
    }

    //OM订单管理用，验资验券检查订单
    public MsgResult CheckOrder(NewOrder order) {
        int oid = getOrderID();
        order.setOrderID(oid);
        MsgResult rst = posTable.get(order.getAccountCode()).CheckOrder(order);
        return rst;
    }

    public MsgResultList CheckOrder(BasketOrders orders) {
        if (!orders.isIsAllPassOrFail()) {
            /*
            if (!orders.isIsMultiAccountCode()) {
                orders.getOrders().stream().forEach((NewOrder o) -> {
                    o.setOrderID(getOrderID());
                });
                MsgResultList rstl= posTable.get(orders.getOrders().get(0).getAccountCode()).CheckOrder(orders);
                rstl.getBasketOrderCheckRST().stream().forEach((MsgResult r)->{
                    if (r.isSuccess()){
                        saveOrder(oid, order);
                    }
                });
                return rstl;
            } else {
             */
            MsgResultList rstlist = new MsgResultList();
            List<MsgResult> ls = new ArrayList<>(orders.getBasketTatol());
            orders.getOrders().stream().forEach((NewOrder o) -> {
                ls.add(CheckOrder(o));
            });
            rstlist.setBasketOrderCheckRST(ls);
            return rstlist;
            //    }
        } else {
            return CheckBasketOrder(orders);
        }

    }

    public MsgResultList CheckBasketOrder(BasketOrders orders) {
        if (!orders.isIsMultiAccountCode()) {
            orders.getOrders().stream().forEach((NewOrder o) -> {
                o.setOrderID(getOrderID());
            });
            return posTable.get(orders.getOrders().get(0).getAccountCode()).CheckBasketOrder(orders);
        } else {
            MsgResultList rstlist = new MsgResultList();
            List<MsgResult> ls = new ArrayList<>(orders.getBasketTatol());
            orders.getOrders().stream().forEach((NewOrder o) -> {
                ls.add(CheckOrder(o));
            });
            rstlist.setBasketOrderCheckRST(ls);
            return rstlist;
        }
    }

    public MsgResult CheckOrder(AlterOrder alterOrder) {
        MsgResult rst = posTable.get(alterOrder.getAccountCode()).CheckOrder(alterOrder);
        //    newOrderTable.put(alterOrder.getOrderID(), order);
        return rst;
    }
    //MM管理功能用，出入金

    public MsgResult FundTransfer(String accountcode, double amount) {
        return posTable.get(accountcode).TranseferFund(amount);
    }

    //交易回报用
    /*
     1.委托回报：MsgType:C1：下单回报，C2:撤单回报,C3:改价回报
     1)模拟成交：OR:订单委托回报，OS:订单成交回报；CR:撤单委托回报，CS:撤单成交回报；AR改单委托回报，AS：改单成交回报；OO：其他指令单回报
     2）内部成交：IS:内部成交回报，IC：内部撤单回报，IA: 内部改单回报；注意，内部成交不需要委托确认，直接处理结果
     3）内部移仓：PS：内部移仓成交回报
     4）状态修订：ST:状态修复回报
     2.多态处理，接收3种委托
     type:1.模拟成交，2.内部成交，3.内部移仓，4.状态修改；OrderType只在type为1的时候有效
     */
    public void OnTradeReport(TradeReportDetail report) {
        //1.第一步补充数据，消息处理
        String acc = report.getAccountCode();
        if (posTable.containsKey(acc)) {
            posTable.get(acc).OnTradeReport(report);
        }
        //4.回复用户
    }

    //计算盈亏
    public void OnCalcPosValue(Price price) {

    }

    @Override
    public void OnPrice(Price price) {
        
    }

}
